﻿using Microsoft.Graphics.Canvas;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.System.Threading;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;
using 纸片人.AttributeUsageFloder;

// https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板

namespace 纸片人.PageViews
{
    [LastModified("2022-5-12", "create GaussianBlurPage.xaml")]
    [PageType("cpu", "高斯模糊")]
    /// <summary>
    /// 可用于自身或导航至 Frame 内部的空白页。
    /// </summary>
    public sealed partial class GaussianBlurPage : Page
    {

        Color[] colors;
        int imageWidth, imageHeight;
        int maxWidth, maxHeight;
        Color[] tempColors;
        int blurRaduis = 1;
        List<double> blurArray;



        WriteableBitmap wb;


        CanvasDevice device = new CanvasDevice();

        public GaussianBlurPage()
        {
            this.InitializeComponent();

            blurArray = new List<double>();
            SetBlurArray();

        }

        private async void selectImage_Click(object sender, RoutedEventArgs e)
        {
           

         

            FileOpenPicker picker = new FileOpenPicker();
            picker.FileTypeFilter.Add(".jpg");
            picker.FileTypeFilter.Add(".png");

            StorageFile file = await  picker.PickSingleFileAsync();

            CanvasBitmap bitmap = await CanvasBitmap.LoadAsync(device, await file.OpenReadAsync());

            imageWidth =(int) bitmap.Size.Width;
            imageHeight = (int)bitmap.Size.Height;

            maxWidth = imageWidth - 1;
            maxHeight = imageHeight - 1;

            colors = bitmap.GetPixelColors();
            tempColors = new Color[colors.Length];
            wb = new WriteableBitmap(imageWidth, imageHeight);

            WriteableBitmap bi = new WriteableBitmap(imageWidth, imageHeight);

          

            bitmap.GetPixelBytes().CopyTo(bi.PixelBuffer);

            image.Source = bi;
            bitmap.Dispose();

          
        }

        #region
        Color GetPixelColor(int x, int y)
        {

            if (x<=0)
            {
                x = 0;
            }
            if (y<=0)
            {
                y = 0;
            }

            int position = x + imageWidth * y;
            if (position > colors.Length - 1)
            {
                position = colors.Length - 1;
            }

            return colors[position];
        }



        void NormalBlur()
        {

            for (int y = 0; y < imageHeight - 1; y++)
            {
                for (int x = 0; x < imageWidth - 1; x++)
                {

                    int lx = x - 1, rx = x + 1, ty = y - 1, by = y - 1;

                    Color lTop, top, rTop,
                        left, center, right,
                        lBom, bom, rBom;


                    lTop = GetPixelColor(lx, ty);
                    top = GetPixelColor(x, ty);
                    rTop = GetPixelColor(rx, ty);

                    left = GetPixelColor(lx, y);
                    center = GetPixelColor(x, y);
                    right = GetPixelColor(rx, y);

                    lBom = GetPixelColor(lx, by);
                    bom = GetPixelColor(x, by);
                    rBom = GetPixelColor(rx, by);



                    int r, g, b;

                    r = lTop.R + top.R + rTop.R + left.R + center.R + right.R + lBom.R + bom.R + rBom.R;
                    g = lTop.G + top.G + rTop.G + left.G + center.G + right.G + lBom.G + bom.G + rBom.G;
                    b = lTop.B + top.B + rTop.B + left.B + center.B + right.B + lBom.R + bom.B + rBom.B;

                    r = r / 9;
                    g = g / 9;
                    b = b / 9;

                    tempColors[x + imageWidth * y] = Color.FromArgb(255, (byte)r, (byte)g, (byte)b);



                }
            }



            using (var b = CanvasBitmap.CreateFromColors(device, tempColors, imageWidth, imageHeight))
            {



                byte[] currentByte = b.GetPixelBytes();
                currentByte.CopyTo(wb.PixelBuffer);
                wb.Invalidate();
                image1.Source = wb;

                b.Dispose();
            }

        }

        #endregion
        async Task ccAsync()
        {
            

           



            for (int y = 0; y < imageHeight-1; y++)
            {
                for (int x = 0; x < imageWidth-1; x++)
                {

                  

                    var nC = GetBlurColor(x, y);
                    //return null;
                    tempColors[x + imageWidth * y] = nC;
                }
            }

            Function.InitialImage(tempColors, imageWidth, imageHeight, image1);
           
        }

        private async void  gaussianBlur_Click(object sender, RoutedEventArgs e)
        {





            List<IAsyncAction> list = new List<IAsyncAction>();
            int mw = imageWidth / 4;
            int mh = imageHeight / 3;

            int w = 0;
            int h = 0;

            for (int i = 1; i <= 4; i++)
            {
                h = 0;
                for (int j = 1; j <= 3; j++)
                {
                    int sx = w;
                    int sy = h;

                    int ex = mw * i;
                    int ey = mh * j;
                    ex = ex > imageWidth - 2 ? imageWidth - 2 : ex;
                    ey = ey > imageHeight - 2 ? imageHeight - 2 : ey;
                    list.Add(Windows.System.Threading.ThreadPool.RunAsync(p =>
                    {
                        pool(sx, sy, ex, ey);
                    }));

                    h = mh * j;
                }

                w = mw * i;


            }


       



            Task.WaitAll(list.Select(p => p.AsTask()).ToArray());
            Function.InitialImage(tempColors, imageWidth, imageHeight, image1);
            //NormalBlur();
            //ccAsync();

        }


   void pool(int sx,int sy,int ex,int ey)
        {
            for (int y = sy; y < ey ; y++)
            {
                for (int x = sx; x <ex; x++)
                {



                    var nC = GetBlurColor(x, y);
                    //return null;
                    tempColors[x + imageWidth * y] = nC;
                }
            }
        }


     
     
        private Color GetBlurColor(int x,int y)
        {
            double r = 0, g = 0, b = 0;
            int index = 0;
            string str = string.Empty;

            //str += "原点 x:" + x + " y:" + y;

            for (var t = y - this.blurRaduis; t <= y + this.blurRaduis; t++)
            {
                for (var l = x - this.blurRaduis; l <= x + this.blurRaduis; l++)
                {

                  

                    var color = GetDefautColor(l, t);
                    var weighValue = blurArray[index];
                    r += color.R * weighValue;
                    g += color.G * weighValue;
                    b += color.B * weighValue;

                    //str += "  [x:" + l + "  y:" + t +"]";

                    index++;
                }
            }

            //Debug.WriteLine(str);
            return Color.FromArgb(255, (byte)(r ), (byte)(g ), (byte)(b ));


        }


        private Color  GetDefautColor(int x,int y)
        {

            x = Math.Min(x, maxWidth);
            y = Math.Min(y, maxHeight);

            if (x <= 0)
            {
                x = 0;
            }
            if (y <= 0)
            {
                y = 0;
            }



            int position = x + imageWidth * y;

        
            if (position > colors.Length - 1)
            {
                position = colors.Length - 1;
            }

            return colors[position];

            
        }

        private void gaussianBlur_Click1(object sender, RoutedEventArgs e)
        {
            ccAsync();
        }

        private void radiusSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
        {
            blurRaduis = (int)e.NewValue;
            if (e.NewValue != e.OldValue)
            {
                SetBlurArray();
            }
  
        }

        private void radiusSlider_DropCompleted(UIElement sender, DropCompletedEventArgs args)
        {
            SetBlurArray();
        }

        void SetBlurArray()
        {

            blurArray = new List<double>();

            int blur = this.blurRaduis;
            double sum = 0;
            for (var y = blur; y >= blur * -1; y--)
            {
                for (var x = blur * -1; x <= blur; x++)
                {
                    var d = GetWeighing(x, y);
                    this.blurArray.Add(d);
                    sum += d;
                }
            }
            for (var i = 0; i < this.blurArray.Count; i++)
                this.blurArray[i] = this.blurArray[i] / sum;
        }

        private double GetWeighing(int x, int y)
        {
            double q = (this.blurRaduis * 2 + 1) / 2;
            return 1 / (2 * Math.PI * Math.Pow(q, 2)) * Math.Exp(-(x * x + y * y) / (2 * q * q));
        }
    }

   
}
